#include "pch.hpp"
#include "MainArea.hpp"

#include "ScriptEditWindow.hpp"
#include "UiEditWindow.hpp"

using namespace Engine;
using namespace Engine::Edit;




MainArea::MainArea(QWidget* parent)
	: QWidget(parent)
	, m_area(this)
{
	QHBoxLayout* layout = new QHBoxLayout(this);
	layout->setContentsMargins(0, 0, 0, 0);
	layout->addWidget(&m_area);
	m_area.setViewMode(QMdiArea::TabbedView);

	verify(connect(&m_area, SIGNAL(subWindowActivated(QMdiSubWindow*)), SLOT(onSubWindowActivated(QMdiSubWindow*))));
}
///////////////////////////////////////////////////////////////////////////////////////////////////

MainArea::~MainArea()
{}
///////////////////////////////////////////////////////////////////////////////////////////////////




void MainArea::setProject(Project::ptr project)
{
	if(m_project)
	{
		m_project->modified.disconnect(boost::bind(&MainArea::projectModified, this, _1, _2, _3));
	}

	closeAllDocuments();
	m_project.reset();

	if(project)
	{
		m_project = project;

		m_project->modified.connect(boost::bind(&MainArea::projectModified, this, _1, _2, _3));
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void MainArea::changeState(State::Type state)
{
	m_state = state;

	foreach(QMdiSubWindow* subWindow, m_area.subWindowList())
	{
		DocumentWindow* window = dynamic_cast<DocumentWindow*>(subWindow->widget());
		if(window)
		{
			window->changeState(state);
			return;
		}
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////////

bool MainArea::isWindowModified() const
{
	if(__super::isWindowModified())
		return true;

	foreach(QMdiSubWindow* subWindow, m_area.subWindowList())
	{
		DocumentWindow* window = dynamic_cast<DocumentWindow*>(subWindow->widget());
		if(window && window->isWindowModified())
			return true;
	}

	return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

QMdiArea::ViewMode MainArea::viewMode() const
{
	return m_area.viewMode();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void MainArea::setViewMode(QMdiArea::ViewMode mode)
{
	m_area.setViewMode(mode);
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void MainArea::show(ProjectItem::ptr item)
{
	// First we will look through all opened windows: if any one
	// already shows that script then we will simply bring that one to the front
	foreach(QMdiSubWindow* subWindow, m_area.subWindowList())
	{
		DocumentWindow* window = dynamic_cast<DocumentWindow*>(subWindow->widget());
		if(window && window->item() == item)
		{
			m_area.setActiveSubWindow(subWindow);
			return;
		}
	}

	// There is no window for this item: Create one
	if(boost::shared_dynamic_cast<Script>(item))
		add(new ScriptEditWindow(boost::shared_static_cast<Script>(item), nullptr));
	else if(boost::shared_dynamic_cast<UiDefinition>(item))
		add(new UiEditWindow(boost::shared_static_cast<UiDefinition>(item), nullptr));
}
///////////////////////////////////////////////////////////////////////////////////////////////////

bool MainArea::close(ProjectItem::ptr item)
{
	foreach(QMdiSubWindow* window, m_area.subWindowList())
	{
		auto documentWindow = dynamic_cast<DocumentWindow*>(window->widget());
		if(documentWindow && documentWindow->item() == item)
		{
			QCloseEvent event;
			QApplication::sendEvent(window, &event);
			if(event.isAccepted())
				return true;
			else
				return false;
		}
	}

	// If there is no window displaying that item, then it can
	// be closed
	return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void MainArea::saveAll()
{
	foreach(QMdiSubWindow* window, m_area.subWindowList())
	{
		DocumentWindow* w = dynamic_cast<DocumentWindow*>(window->widget());
		verify(w);
		w->save();
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void MainArea::closeAllDocuments()
{
	m_area.closeAllSubWindows();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

DocumentWindow* MainArea::active() const
{
	auto window = m_area.activeSubWindow();
	if(!window)
		return nullptr;

	return dynamic_cast<DocumentWindow*>(window->widget());
}
///////////////////////////////////////////////////////////////////////////////////////////////////

std::size_t MainArea::numDocuments() const
{
	return m_area.subWindowList().size();
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void MainArea::onSubWindowActivated(QMdiSubWindow* window)
{
	if(!window)
		return;

	auto document = dynamic_cast<DocumentWindow*>(window->widget());
	if(!document)
		return;

	emit activeDocumentChanged(document);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void MainArea::onSubWindowClosed(DocumentWindow* window)
{
	emit windowRemoved(window);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

ProjectItem::Result MainArea::projectModified(ProjectItem::weak_ptr sender, ProjectItem::weak_ptr _item, ProjectItem::Action action)
{
	auto item = _item.lock();

	switch(action)
	{
	case ProjectItem::EndAddChild:
		show(item);
		break;
	}

	return ProjectItem::Agree;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void MainArea::add(DocumentWindow* window)
{
	window->changeState(m_state);
	auto subWindow = new QMdiSubWindow(&m_area);
	subWindow->setAttribute(Qt::WA_DeleteOnClose);
	subWindow->setWidget(window);
	m_area.addSubWindow(subWindow);
	subWindow->showMaximized();

	verify(connect(window, SIGNAL(closed(DocumentWindow*)), SLOT(onSubWindowClosed(DocumentWindow*))));

	emit windowAdded(window);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
